package eu.webhib.frmwrk.jsf.exception;

import eu.webhib.frmwrk.jsf.utils.JsfUtil;
import eu.webhib.frmwrk.servlet.AbstractApplication;
import java.util.Iterator;
import javax.faces.FacesException;
import javax.faces.context.ExceptionHandler;
import javax.faces.context.ExceptionHandlerWrapper;
import javax.faces.event.ExceptionQueuedEvent;
import javax.faces.event.ExceptionQueuedEventContext;
import org.apache.log4j.Logger;

/**
 * Exception handler for exception raised in JSF context.
 * Used to deliver unexpected internal error to the user interface and to show a specific error page.
 * At certain JSF implementations the exceptions are otherwise caught and not delivered up to the
 * main servlet.
 */
public class ApplExceptionHandler extends ExceptionHandlerWrapper {

   private static final Logger log = Logger.getLogger(ApplExceptionHandler.class);
   private ExceptionHandler wrapped;

   public ApplExceptionHandler(ExceptionHandler wrapped) {
      log.trace("FrmExceptionHandler");
      this.wrapped = wrapped;
   }

   @Override
   public ExceptionHandler getWrapped() {
      return wrapped;
   }

   @Override
   public void handle() throws FacesException {
      log.trace("handle");

      /** Iterate over all not handled exceptions */
      Iterator<ExceptionQueuedEvent> i = getUnhandledExceptionQueuedEvents().iterator();
      while (i.hasNext()) {
         ExceptionQueuedEvent event = i.next();
         ExceptionQueuedEventContext context = (ExceptionQueuedEventContext) event.getSource();
         /** obtain the Throwable object */
         Throwable t = context.getException();
         
         try {
            log.fatal("\n" + ExceptionUtil.getStackTrace(t));
            /** redirect to error page */
            JsfUtil.sendRedirect(AbstractApplication.getInstance().getErrorPageURI());
            /** set exception information to session so error page could print them out */
            JsfUtil.setSessionAttribute(JsfUtil.SESSION_EXCEPTION_ATTRIBUTE, t);
            return;
         } finally {
            /** after exception is handled, remove it from queue */
            i.remove();
         }
      }
      /** let the parent handle the rest */
      getWrapped().handle();
   }
}